#pragma once // 防止头文件被重复包含
#include "TCP_Serve.hpp"
#include "task.hpp"
#include <iostream>
#include <sys/socket.h>
#include "log.hpp"
#include "ThreadPools.hpp"
#include <memory>
#include "epoll.hpp"

#define PORT 12345 // 端口号

class httpserve
{
private:
  int _port;          // 端口
  tcp_serve *tcp_s;   // tcp服务对象指针
  thread *thread_ptr; // 线程池服务的指针
  Epoll epoll;        // epoll模型
  int state_s;        // 服务的状态
  int _fd;            // 网络文件描述符

public:
  httpserve(int port = PORT)
      : _port(port), state_s(1), _fd(-1)
  {
  }

  void init_http_serve() // 初始化服务
  {
    tcp_s = tcp_serve::git_tcp_object(_port);
    thread_ptr = thread::get_thread();
    struct sigaction sa;
    // 初始化sigaction结构体
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = SIG_IGN; // 设置为SIG_IGN来忽略SIGPIPE信号
    // 绑定SIGPIPE信号到新的处理函数（即忽略它）
    if (sigaction(SIGPIPE, &sa, NULL) == -1)
    {
      LOG(WARNING, "SIGPIPE信号屏蔽失败，http写入失败时会崩溃");
    }

    epoll.EpollCtl(EPOLL_CTL_ADD, tcp_s->get_fd(), epollin); // 在epoll模型中注册监听套接字
  }

  void start_http_serve() // 启动服务
  {
    int socket_fd = tcp_s->get_fd();
    struct sockaddr_in socket_c;
    socklen_t tmp = sizeof(socket_c);       // 结构体大小
    memset(&socket_c, 0, sizeof(socket_c)); // 把结构体初始化为0
    LOG(INFO, "服务启动中...");

    struct epoll_event ev[Scooping_size];
    while (state_s)
    {
      //  _fd = accept(socket_fd, (struct sockaddr *)&socket_c, &tmp); // 获取新连接

      int n = epoll.EpollWait(ev);
      if (-1 == n)
      {
        LOG(WARNING, "文件描述符等待失败");
      }
      else if (0 == n)
      {
        LOG(WARNING, "文件描述符等待超时");
      }
      else
      {
        for (int i = 0; i < n; i++)
        {
          int fd = ev[i].data.fd;
          if (socket_fd == fd) // 说明套接字文件描述符已经准备就绪
          {
            _fd = accept(fd, (struct sockaddr *)&socket_c, &tmp); // 获取新连接
            epoll.EpollCtl(EPOLL_CTL_ADD, _fd, epollin);
          }
          else
          {
            task t(fd);
            thread_ptr->push(t);
          }
        }
      }
    }
  }
};
